#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <UIKit/UIApplication.h>
#import <SpringBoard/SBApplicationController.h>
#import <SpringBoard/SBApplication.h>
#import <LockInfo/Plugin.h>

#import "framework/FWCommon.h"
#import "framework/FWPlugin.h"
#import "framework/FWApplication.h"
#import "framework/FWPopupView.h"

#import "PICommon.h"
#import "PITaskPlugin.h"
#import "PIIntegration.h"
#import "PITaskIntegration.h"
#import "PITaskPreview.h"
#import "PIContextList.h"
#import "PIContextSelectList.h"
#import "PITaskCreate.h"
#import "PITaskSearch.h"
#import "PITaskListAccess.h"
#import "PITaskStatus.h"
#import "PITaskDebug.h"
#import "PITaskNative.h"
#import "PITaskIntegration.h"


NSString* const kPITaskCompletionMode = @"completeTasks";
FWAccessoryActionType const kPITaskCompletionModeDefault = FWAccessoryActionTypeTap;


@implementation PITaskPlugin

@synthesize contexts, contextsString, eventStore, eventStoreUpdated;


// ******************************************************************************************
#pragma mark -
#pragma mark Initialisation and object management

- (id)initWithApplication:(FWApplication*)app
{
    if ((self = [super initWithApplication:app name:@"PITask"])) {
        self.eventStore = [[[EKEventStore alloc] init] autorelease];
        self.eventStoreUpdated = NO;

        self.fwDatasource = [[[PITaskListAccess alloc] init] autorelease];
        
        accessoryType = kPITaskCompletionModeDefault;
    }
    
    return self;
}

- (void)dealloc
{
    [contexts release];
    [contextsString release];
    [eventStore release];
    
    [super dealloc];
}


// ******************************************************************************************
#pragma mark -
#pragma mark Application status management

- (void)application:(FWApplication*)application updateApplicationPrefs:(NSDictionary*)prefs pluginPrefs:(FWPreferences*)pluginPrefs
{
    PITaskStatus* status = (PITaskStatus*)application.info;
    
    [PIIntegration updateInfoFromPrefs:prefs application:application];
    
    // Turn off auto contexts if PI has turned them off
    if (![PIIntegration locationMonitoringForPrefs:prefs]) {
        if (status.isAutoContextOn) {
            status.autoContextOn = NO;
            status.autoContextAvailable = NO;
            status.captionValue = nil;
            
            // Clear any contexts we're using
            [application clearAttribute:kPIApplicationContextLocation];
            
            XLog(@"LI:PITask: Disabling location monitoring as PI has it disabled");
        }
    }
    else
        status.autoContextAvailable = YES;
}

- (void)updatePrefrences:(FWPreferences *)prefs
{
    accessoryType = (FWAccessoryActionType)[prefs intValue:kPITaskCompletionMode withDefault:kPITaskCompletionModeDefault];
}

- (BOOL)updateApplication:(FWApplication*)application
{
    if (!application.info)
        application.info = [[[PITaskStatus alloc] init] autorelease];

    BOOL response = [super updateApplication:application];

    // Get the badge number if there is one
    Class displayCls = objc_getClass("SBDisplay");
    NSNumber* badge = [displayCls defaultValueForKey:@"SBApplicationBadgeKey"
                                   displayIdentifier:self.appDisplayIdentifier
                                           urlScheme:self.appURLScheme];
    if (badge) {
        XLog(@"LI:PITask: Initial badge value = %@", badge);
        ((PITaskStatus*)application.info).badgeValue = [badge stringValue];
    }
    
    // If PI has location contexts on then so should we
    PITaskStatus* status = (PITaskStatus*)application.info;
    NSDictionary* prefs = [NSDictionary dictionaryWithContentsOfFile:application.preferencesPath];
    status.autoContextOn = status.autoContextAvailable = [PIIntegration locationMonitoringForPrefs:prefs];
    if (status.autoContextOn) {
        if ([PITaskIntegration numberOfLocationContexts:application] == 0)
            status.autoContextOn = NO;
    }

    [application setAttribute:kPIApplicationContextLocation value:[PIIntegration locationContextsFromPI]];
    
    NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
    [center addObserver:self
               selector:@selector(badgeUpdate:)
                   name:[self.appBundleIdentifier stringByAppendingString:LIBadgeChangedNotification]
                 object:nil];
    
    // Notification sent when iOS reminders are updated
    [center addObserver:self selector:@selector(remindersUpdated:) name:@"EKEventStoreChangedNotification" object:eventStore];
    
    return response;
}


// ******************************************************************************************
#pragma mark -
#pragma mark Update checking

- (BOOL)application:(FWApplication*)application shouldUpdateForDate:(NSDate*)date
{
    // Let the datasource handle update control
    return NO;
}


// ******************************************************************************************
#pragma mark -
#pragma mark Reminder database update callback

- (void)remindersUpdated:(NSNotification*)notif
{
    DebugLog(@"LI:PITask: iOS reminders update %@", notif);
    
    self.eventStoreUpdated = YES;
    [self triggerUnconditionalRefresh];
}


// ******************************************************************************************
#pragma mark -
#pragma mark Toolbar button callbacks

- (void)displayPopupMessage:(NSString*)msg
{
    // Don't show if popups are disabled
    if (![FWPreferences boolValue:kPIOptionsShowPopups withDefault:kPIOptionsShowPopupsDefault preferences:self.liPlugin.preferences])
        return;

    UIView* view = FWLITableView();
    if (view)
        [FWPopupView displayPopupMessage:msg forView:view];
}

- (void)toggleMenuClicked:(UIBarButtonItem*)sender
{
    if ([self isToolbarVisible])
        [self hideToolbar];
    else
        [self setToolbarIndex:0];
}

- (void)toggleDetailsClicked:(UIBarButtonItem*)sender
{
    NSBundle* bundle = [NSBundle bundleForClass:[self class]];
    PITaskStatus* status = (PITaskStatus*)self.fwApplication.info;
    
    [self displayPopupMessage:localize(bundle, !status.isToggleOn ? @"Status/Details/Hide" : @"Status/Details/Show")];
    [self hideToolbar];

    status.toggleOn = !status.isToggleOn;
    [self performSelectorInBackground:@selector(redisplayListOnNewThread:) withObject:self];
}

- (void)disableContextsClicked:(UIBarButtonItem*)sender
{
    // Turn off automatic context updates
    PITaskStatus* status = (PITaskStatus*)self.fwApplication.info;
    status.autoContextOn = NO;
    status.fixedContextOn = NO;
    status.captionValue = nil;
    
    // Clear any contexts we're using
    [self.fwApplication clearAttribute:kPIApplicationContextLocation];
    [self.fwApplication clearAttribute:kPIApplicationContextFixed];
    
    // Get new data
    [self displayPopupMessage:localize([NSBundle bundleForClass:[self class]], @"Status/Context/Off")];

    [self hideToolbar];
    [self updateStatusbar];
    [self triggerUnconditionalRefresh];
}

- (void)locationContextClicked:(UIBarButtonItem*)sender
{
    NSNumber* show = [self.liPlugin.preferences objectForKey:kPIOptionsShowLocationPage];
    if (!show)
        show = [NSNumber numberWithBool:kPIOptionsShowLocationPageDefault];

    if (![show boolValue]) {
        NSArray* locations = [PIIntegration locationContextsFromPI];
        [self.fwApplication setAttribute:kPIApplicationContextLocation value:locations];
        
        PITaskStatus* status = (PITaskStatus*)self.fwApplication.info;
        status.autoContextOn = YES;

        // Turn off fixed context mode if not combining contexts
        BOOL combineMode = [FWPreferences boolValue:kPITaskOptionsCombineContexts
                                        withDefault:kPITaskOptionsCombineContextsDefault
                                        preferences:self.liPlugin.preferences];
        status.fixedContextOn = status.fixedContextOn && combineMode;
        
        [self displayPopupMessage:localize([NSBundle bundleForClass:[self class]], @"Status/Context/Locations")];

        [self hideToolbar];
        [self updateStatusbar];
        [self triggerUnconditionalRefresh];
    }
    else {
        PIContextList* previewData = [[[PIContextList alloc] initWithPreferences:self.preferences] autorelease];
        
        FWDetailListView *thePreview = [[[FWDetailListView alloc] initWithFrame:[self previewCompatibleRect]
                                                                           list:[NSArray arrayWithObjects:@"X", nil]
                                                                          index:0
                                                                        caption:@"ListView/Locations"
                                                                    application:self.fwApplication
                                                                       delegate:previewData] autorelease];
        
        [self.liPlugin showPreview:[self previewCompatibleView:thePreview]];
    }
}

-(void)manualContextClicked:(UIBarButtonItem*)sender
{
    PIContextSelectList* previewData = [[[PIContextSelectList alloc] initWithKey:kPIApplicationContextList1
                                                                     preferences:self.preferences] autorelease];

    FWDetailListView *thePreview = [[[FWDetailListView alloc] initWithFrame:[self previewCompatibleRect]
                                                                       list:[NSArray arrayWithObjects:@"X", nil]
                                                                      index:0
                                                                    caption:@"ListView/Contexts"
                                                                application:self.fwApplication
                                                                   delegate:previewData] autorelease];

    [self.liPlugin showPreview:[self previewCompatibleView:thePreview]];
}

-(void)newTodoClicked:(UIBarButtonItem*)sender
{
    PITaskCreate* newTodo = [[[PITaskCreate alloc] initWithFrame:[self previewCompatibleRect]
                                                     application:self.fwApplication
                                                     preferences:self.preferences] autorelease];

    [self.liPlugin showPreview:[self previewCompatibleView:newTodo]];
}

-(void)searchTodoClicked:(UIBarButtonItem*)sender
{
    PITaskSearch* searchTodo = [[[PITaskSearch alloc] initWithFrame:[self previewCompatibleRect]
                                                        application:self.fwApplication
                                                        preferences:self.preferences] autorelease];
    
    [self.liPlugin showPreview:[self previewCompatibleView:searchTodo]];
}

- (void)previewSelected:(LIAction *)action data:(LIData *)data
{
    if (![data.uniqueID isEqualToString:kUniqueIdInfo])
        [super previewSelected:action data:data];
    else if (self.isDebugMode) {
        PITaskDebug* view = [[[PITaskDebug alloc] init] autorelease];
        FWDetailListView *thePreview = [[[FWDetailListView alloc] initWithFrame:[self previewCompatibleRect]
                                                                           list:[NSArray arrayWithObjects:@"X", nil]
                                                                          index:0
                                                                        caption:localize([NSBundle bundleForClass:[self class]], @"Debug View/Title")
                                                                    application:self.fwApplication
                                                                       delegate:view] autorelease];
        view.controlDelegate = thePreview;

        [self.liPlugin showPreview:[self previewCompatibleView:thePreview]];
    }
}


// ******************************************************************************************
#pragma mark -
#pragma mark Badge update callback

- (void)badgeUpdate:(NSNotification*)notif
{
    if (self.isPocketInformantPresent) {
        if (NSNumber* badge = [notif.userInfo objectForKey:@"badge"]) {
            XLog(@"LI:PITask: badge update %@", notif);
            
            NSString* value = [badge stringValue];

            if (![((PITaskStatus*)self.fwApplication.info).badgeValue isEqualToString:value]) {
                XLog(@"LI:PITask: New badge value: %@", value);

                ((PITaskStatus*)self.fwApplication.info).badgeValue = value;
                if ([self.preferences boolValue:kPIOptionsShowBadge withDefault:kPIOptionsShowBadgeDefault])
                    [self updateStatusbar]; 
            }
        }
    }
}


// ******************************************************************************************
#pragma mark -
#pragma mark Managing the status bar

static NSInteger const kMenuOpenBtnTag = 1;

- (NSString*)statusbarCaptionValue
{
    return ((PITaskStatus*)self.fwApplication.info).captionValue;
}

- (NSString*)statusbarCaptionIcon
{
    PITaskStatus* status = (PITaskStatus*)self.fwApplication.info;
    
    if (status.isAutoContextOn) {
        if (NSArray* items = [self.fwApplication getAttribute:kPIApplicationContextLocation]) {
            if (items.count > 0)
                return @"locate-mode";
        }
        return @"nolocate-mode";
    }
    else if (status.isFixedContextOn)
        return @"favorite-mode";

    return nil;
}

- (NSString*)statusbarCaptionIcon2
{
    PITaskStatus* status = (PITaskStatus*)self.fwApplication.info;
    
    if (status.isAutoContextOn && status.isFixedContextOn)
        return @"favorite-mode";
    
    return nil;
}

- (NSString*)statusbarBadgeValue
{
    if ([self.preferences boolValue:kPIOptionsShowBadge withDefault:kPIOptionsShowBadgeDefault])
        return ((PITaskStatus*)self.fwApplication.info).badgeValue;
    else
        return nil;
}

- (NSArray*)statusbarItems
{
    NSBundle* bundle = [NSBundle bundleForClass:[self class]];
    
    UIBarButtonItem* menuOpenBtn = [[[UIBarButtonItem alloc]
                                     initWithImage:[UIImage imageWithContentsOfFile:
                                                    [bundle pathForResource:@"menuopen" ofType:@"png"]]
                                     style:UIBarButtonItemStylePlain
                                     target:self
                                     action:@selector(toggleMenuClicked:)] autorelease];
    menuOpenBtn.tag = kMenuOpenBtnTag;
    
    NSArray* navItems = [NSArray arrayWithObject:menuOpenBtn];
    return navItems;
}

- (NSInteger)statusbarIndent
{
    return 35;
}

- (void)performSwipeAction:(UISwipeGestureRecognizerDirection)direction
{
    NSURL* url = [NSURL URLWithString:@"informant://displayItem"];
    [self.fwApplication.fwPlugin.liPlugin launchURL:url];
}


// ******************************************************************************************
#pragma mark -
#pragma mark Managing the status bar

- (NSArray*)toolbarItems
{
    NSBundle* bundle = [NSBundle bundleForClass:[self class]];
    PIPlugin* plugin = (PIPlugin*)self.fwApplication.fwPlugin;

    PITaskStatus* status = (PITaskStatus*)self.fwApplication.info;
    BOOL combineMode = [FWPreferences boolValue:kPITaskOptionsCombineContexts
                                    withDefault:kPITaskOptionsCombineContextsDefault
                                    preferences:self.liPlugin.preferences];
    
    UIBarButtonItem* closeBtn = [[[UIBarButtonItem alloc]
                                  initWithImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"menuclose" ofType:@"png"]]
                                  style:UIBarButtonItemStylePlain
                                  target:self
                                  action:@selector(toggleMenuClicked:)] autorelease];
    
    UIBarButtonItem* locationBtn = [[[UIBarButtonItem alloc]
                                     initWithImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"locate" ofType:@"png"]]
                                     style:UIBarButtonItemStylePlain
                                     target:self
                                     action:@selector(locationContextClicked:)] autorelease];
#ifdef DEVELOPMENT_MODE
    locationBtn.enabled = !status.isAutoContextOn;
#else
    locationBtn.enabled = status.isAutoContextAvailable && !status.isAutoContextOn;
#endif
    
    UIBarButtonItem* newTodoBtn = [[[UIBarButtonItem alloc]
                                    initWithImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"newtodo" ofType:@"png"]]
                                    style:UIBarButtonItemStylePlain
                                    target:self
                                    action:@selector(newTodoClicked:)] autorelease];
    
    UIBarButtonItem* favoriteBtn = [[[UIBarButtonItem alloc]
                                     initWithImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"favorite2" ofType:@"png"]]
                                     style:UIBarButtonItemStylePlain
                                     target:self
                                     action:@selector(manualContextClicked:)] autorelease];
    
    UIBarButtonItem* detailsBtn = [[[UIBarButtonItem alloc]
                                    initWithImage:[UIImage imageWithContentsOfFile:
                                                   [bundle pathForResource:status.isToggleOn ? @"expand" : @"contract" ofType:@"png"]]
                                    style:UIBarButtonItemStylePlain
                                    target:self
                                    action:@selector(toggleDetailsClicked:)] autorelease];

    UIBarButtonItem* searchBtn = [[[UIBarButtonItem alloc]
                                    initWithImage:[UIImage imageWithContentsOfFile:
                                                   [bundle pathForResource:@"search" ofType:@"png"]]
                                    style:UIBarButtonItemStylePlain
                                    target:self
                                    action:@selector(searchTodoClicked:)] autorelease];

    UIBarButtonItem* disableBtn = [[[UIBarButtonItem alloc]
                                    initWithImage:[UIImage imageWithContentsOfFile:[bundle pathForResource:@"cancel" ofType:@"png"]]
                                    style:UIBarButtonItemStylePlain
                                    target:self
                                    action:@selector(disableContextsClicked:)] autorelease];
    disableBtn.enabled = status.isFixedContextOn || status.isAutoContextOn;
    
    UIBarButtonItem *flexSpc = [[[UIBarButtonItem alloc]
                                 initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
                                 target:nil
                                 action:nil] autorelease];
    UIBarButtonItem *fixedSpc = [[[UIBarButtonItem alloc]
                                  initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
                                  target:nil
                                  action:nil] autorelease];
    fixedSpc.width = FWIsDeviceAnIPad() ? 10 : 3;
    
    NSMutableArray* navItems = [NSMutableArray arrayWithObjects:
                                closeBtn, flexSpc, flexSpc, nil];
    
    if (plugin.isPocketInformantPresent && !plugin.isNativeOnly)
        [navItems addObjectsFromArray:[NSArray arrayWithObjects:
                                       locationBtn, fixedSpc,
                                       favoriteBtn, fixedSpc,
                                       disableBtn, flexSpc,
                                       fixedSpc,  nil]];

    [navItems addObjectsFromArray:[NSArray arrayWithObjects:
                                   flexSpc,
                                   detailsBtn, flexSpc,
                                   nil]];

    // Don't display on the lockscreen
    if (!(self.fwApplication.isLockScreen &&
          ![FWPreferences boolValue:kPIOptionsLockPreview
                        withDefault:kPIOptionsLockPreviewDefault
                        preferences:self.fwApplication.fwPlugin.liPlugin.preferences])) {
        if ([FWPreferences boolValue:kPIOptionsShowPreviews withDefault:kPIOptionsShowPreviewsDefault preferences:self.liPlugin.preferences]) {
            [navItems addObject:searchBtn];
            [navItems addObject:flexSpc];
        }
    }
    
    if (!(self.fwApplication.isLockScreen &&
          ![FWPreferences boolValue:kPITaskOptionsLockCreate
                        withDefault:kPITaskOptionsLockCreateDefault
                        preferences:self.fwApplication.fwPlugin.liPlugin.preferences])) {
          if ([self.preferences boolValue:kPIOptionsAddTaskFeature withDefault:kPIOptionsAddTaskFeatureDefault]) {
              [navItems addObject:newTodoBtn];
              [navItems addObject:flexSpc];
          }
      }
    
    return navItems;
}


// ******************************************************************************************
#pragma mark -
#pragma mark Accessory action support

- (FWAccessoryActionType)accessoryActionType:(FWDisplayObject *)item
{
    if (dbVersion >= PIDatabaseVersion250)
        return accessoryType;
    else
        return FWAccessoryActionTypeNone;
}

- (void)performAcessoryAction:(FWDisplayObject *)item
{
    PITask* task = (PITask*)item;
    
    if (!task.isComplete) {
        BOOL success = task.isNative
        ? [PITaskNative completeTask:task application:self.fwApplication]
        : [PITaskIntegration completeTask:task application:self.fwApplication];
        
        if (success) {
            task.completionDate = [NSDate date];
            
            // A native task will generate its own notification
            if (!task.isNative)
                [self triggerUnconditionalRefresh];
        }
        else
            [self displayPopupMessage:localize([NSBundle bundleForClass:[self class]], @"New Task/Complete/Error")];
    }
}

@end
